﻿using System;
using System.Threading;
using System.Drawing;
using System.Drawing.Imaging;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using DShowNET;
using DShowNET.Device;
using System.Runtime.InteropServices;
using System.IO;
using System.Diagnostics;


namespace testCam
{
    ///
    /// Description résumée de Form1.
    ///
    public class Form1 : System.Windows.Forms.Form
    {
        #region Connexion a la dll de Vuzix
        [StructLayout(LayoutKind.Sequential)]
        public struct IWRMagSensor
        {
            [MarshalAs(UnmanagedType.U1)]
            public byte magx_lsb;
            [MarshalAs(UnmanagedType.U1)]
            public byte magx_msb;
            [MarshalAs(UnmanagedType.U1)]
            public byte magy_lsb;
            [MarshalAs(UnmanagedType.U1)]
            public byte magy_msb;
            [MarshalAs(UnmanagedType.U1)]
            public byte magz_lsb;
            [MarshalAs(UnmanagedType.U1)]
            public byte magz_msb;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct IWRAccelSensor
        {
            [MarshalAs(UnmanagedType.U1)]
            public byte accx_lsb;
            [MarshalAs(UnmanagedType.U1)]
            public byte accx_msb;
            [MarshalAs(UnmanagedType.U1)]
            public byte accy_lsb;
            [MarshalAs(UnmanagedType.U1)]
            public byte accy_msb;
            [MarshalAs(UnmanagedType.U1)]
            public byte accz_lsb;
            [MarshalAs(UnmanagedType.U1)]
            public byte accz_msb;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct IWRGyroSensor
        {
            [MarshalAs(UnmanagedType.U1)]
            public byte gyx_lsb;
            [MarshalAs(UnmanagedType.U1)]
            public byte gyx_msb;
            [MarshalAs(UnmanagedType.U1)]
            public byte gyy_lsb;
            [MarshalAs(UnmanagedType.U1)]
            public byte gyy_msb;
            [MarshalAs(UnmanagedType.U1)]
            public byte gyz_lsb;
            [MarshalAs(UnmanagedType.U1)]
            public byte gyz_msb;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct IWRLBGyroSensor
        {
            [MarshalAs(UnmanagedType.U1)]
            public byte gyx_lsb;
            [MarshalAs(UnmanagedType.U1)]
            public byte gyx_msb;
            [MarshalAs(UnmanagedType.U1)]
            public byte gyy_lsb;
            [MarshalAs(UnmanagedType.U1)]
            public byte gyy_msb;
            [MarshalAs(UnmanagedType.U1)]
            public byte gyz_lsb;
            [MarshalAs(UnmanagedType.U1)]
            public byte gyz_msb;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct IWRSENSDATA
        {
            public IWRMagSensor mag_sensor;
            public IWRAccelSensor acc_sensor;
            public IWRGyroSensor gyro_sensor;
            public IWRLBGyroSensor lbgyro_sensor;
        }

        // iWear Tracking DLL Import
        [DllImport("iWearDrv.dll", SetLastError = false, EntryPoint = "IWROpenTracker")]
        public static extern long IWROpenTracker();

        [DllImport("iWearDrv.dll", SetLastError = false, EntryPoint = "IWRCloseTracker")]
        public static extern void IWRCloseTracker();

        [DllImport("iWearDrv.dll", SetLastError = false, EntryPoint = "IWRBeginCalibrate")]
        public static extern long IWRBeginCalibrate();

        [DllImport("iWearDrv.dll", SetLastError = false, EntryPoint = "IWREndCalibrate")]
        public static extern void IWREndCalibrate(bool save);

        [DllImport("iWearDrv.dll", SetLastError = false, EntryPoint = "IWRGetTracking")]
        public static extern long IWRGetTracking(ref int yaw, ref int pitch, ref int roll);

        [DllImport("iWearDrv.dll", SetLastError = false, EntryPoint = "IWRGet6DTracking")]
        public static extern long IWRGet6DTracking(ref int yaw, ref int pitch, ref int roll, ref int x, ref int y, ref int z);

        [DllImport("iWearDrv.dll", SetLastError = false, EntryPoint = "IWRGetSensorData")]
        public static extern long IWRGetSensorData(ref IWRSENSDATA sensorData);

        [DllImport("iWearDrv.dll", SetLastError = false, EntryPoint = "IWRSetFilterState")]
        public static extern void IWRSetFilterState(Boolean on);

        [DllImport("iWearDrv.dll", SetLastError = false, EntryPoint = "IWRZeroSet")]
        public static extern void IWRZeroSet();

        [DllImport("iWearDrv.dll", SetLastError = false, EntryPoint = "IWRGetProductID")]
        public static extern int IWRGetProductID();


        //iWear Stereo DLL Import
        [DllImport("iWrstDrv.dll", EntryPoint = "IWRSTEREO_Open", SetLastError = true)]
        public static extern IntPtr IWRSTEREO_Open();

        [DllImport("iWrstDrv.dll", EntryPoint = "IWRSTEREO_SetStereo")]
        public static extern Boolean IWRSTEREO_SetStereo(IntPtr handle, Boolean enabled);

        [DllImport("iWrstDrv.dll", EntryPoint = "IWRSTEREO_SetLR")]
        public static extern Boolean IWRSTEREO_SetLR(IntPtr handle, Boolean eye);

        [DllImport("iWrstDrv.dll", EntryPoint = "IWRSTEREO_WaitForAck")]
        public static extern Byte IWRSTEREO_WaitForAck(IntPtr handle, Boolean eye);
        #endregion


        public System.Windows.Forms.Panel panel1;
        public System.Windows.Forms.Panel panel2;
        public System.Windows.Forms.PictureBox image1;
        public System.Windows.Forms.PictureBox image2;
        public DsDevice WebcamL = null;
        public DsDevice WebcamR = null;
        public IMediaControl MediaControlL = null;
        public IMediaControl MediaControlR = null;
        private bool TheSwitcher = false;
        public IntPtr IWRHandle;
        public ArrayList Webcamliste;
        ///
        /// Variable nécessaire au concepteur.
        ///
        private System.ComponentModel.Container components = null;
 
        public Form1()
        {
            //
            //
            InitializeComponent();
            //
            //
        }

        ///
        /// Nettoyage des ressources utilisées.
        ///
        protected override void Dispose( bool disposing )
        {
            if( disposing )
            {
                if (components != null)
                {
                    components.Dispose();
                }
            }
            base.Dispose( disposing );
        }

        #region Code généré par le Concepteur Windows Form
        private void InitializeComponent()
        {
            this.panel1 = new System.Windows.Forms.Panel();
            this.panel2 = new System.Windows.Forms.Panel();
            this.image1 = new System.Windows.Forms.PictureBox();
            this.image2 = new System.Windows.Forms.PictureBox();

            this.SuspendLayout();


            //
            // panel1
            //
            this.panel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
            this.panel1.Dock = System.Windows.Forms.DockStyle.Left;
            //this.panel1.Location = new System.Drawing.Point(0, 0);
            this.panel1.Name = "panel1";            
            this.panel1.Size = new System.Drawing.Size(512, 666);
            this.panel1.MouseClick += new MouseEventHandler(ActiveLeftEye);
            this.panel1.TabIndex = 1;

            //
            // panel2
            //
            this.panel2.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
            this.panel2.Dock = System.Windows.Forms.DockStyle.Right;
            //this.panel2.Location = new System.Drawing.Point(0, 0);
            this.panel2.Name = "panel2";
            this.panel2.Size = new System.Drawing.Size(512, 666);
            this.panel2.MouseClick += new MouseEventHandler(ActiveRightEye);
            this.panel2.TabIndex = 2;

            //
            // Image1
            //
            this.image1.Dock = System.Windows.Forms.DockStyle.Left;
            this.image1.Size = new System.Drawing.Size(512, 666);
            this.image1.Name = "image1";

            //
            // Image2
            //
            this.image2.Dock = System.Windows.Forms.DockStyle.Right;
            this.image2.Size = new System.Drawing.Size(512, 666);
            this.image2.Name = "image2";


            //
            // Form1
            //
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.ClientSize = new System.Drawing.Size(1024, 666);
            this.Controls.Add(this.panel1);
            this.Controls.Add(this.panel2);
            /*this.Controls.Add(this.image1);
            this.Controls.Add(this.image2);*/
            this.Name = "Form1";
            this.Text = "RealEye(s)";
            this.Load += new System.EventHandler(this.Form1_Load);
            this.KeyPreview = true;
            this.KeyPress += new KeyPressEventHandler(this.MykeyPress);
            this.ResumeLayout(true);
        }
        #endregion

        private void ActiveLeftEye(object sender, MouseEventArgs e)
        {
            this.MediaControlR.Stop();
            this.MediaControlL.Run();
            this.TheSwitcher = false;
        }

        private void ActiveLeftEye()
        {
            this.MediaControlR.Stop();
            this.MediaControlL.Run();
            this.TheSwitcher = false;
        }

        private void ActiveRightEye(object sender, MouseEventArgs e)
        {
            this.MediaControlL.Stop();
            this.MediaControlR.Run();
            this.TheSwitcher = true;
        }

        private void ActiveRightEye()
        {
            this.MediaControlL.Stop();
            this.MediaControlR.Run();
            this.TheSwitcher = true;
        }

        private void MyMouseClick(object sender, MouseEventArgs e)
        {
            this.switchEye();
        }


        ///
        /// Point d'entrée principal de l'application.
        ///
        [STAThread]
        static void Main()
        {
            Application.Run(new Form1());
        }

        private void Config(DsDevice Webcam, Panel panel, bool test = true)
        {
            ICaptureGraphBuilder2 CaptureGraph = null;
            IGraphBuilder GraphBuilder = null;
            IMediaControl MediaControl = null;
            IBaseFilter FiltreVideoInput = null;
            Guid categorie = PinCategory.Capture;
            Guid media = MediaType.Video;
            int hr;

            //Création du filtre qui contiendra la reference à la cam video
            object objet = null;
            UCOMIMoniker moniker = Webcam.Mon;
            Guid gbasefilter = typeof(IBaseFilter).GUID;
            moniker.BindToObject(null, null, ref gbasefilter, out objet);
            FiltreVideoInput = (IBaseFilter)objet;
            objet = null;
            /////////////////////////////////////////////////


            /* La partie GraphBuilder ne dépend pas des variables précédentes
             * ni des paramètres de la méthodes */


            //Création du GraphBuilder (contenant de filtres, entre autres)
            Type comType = null;
            object ObjetCOM = null;
            comType = Type.GetTypeFromCLSID(Clsid.FilterGraph);
            ObjetCOM = Activator.CreateInstance(comType);
            GraphBuilder = (IGraphBuilder)ObjetCOM;
            //////////////////////////////////////////////////

            /* La partie CaptureGraph ne dépend pas des variables précédentes
            * ni des paramètres de la méthode */
            
            //Création du CaptureGraph pour capturer la video
            ObjetCOM = null;
            Guid clsid = Clsid.CaptureGraphBuilder2;
            Guid gcapture = typeof(ICaptureGraphBuilder2).GUID;
            ObjetCOM = DsBugWO.CreateDsInstance(ref clsid, ref gcapture);
            CaptureGraph = (ICaptureGraphBuilder2)ObjetCOM;
            ObjetCOM = null;
            /////////////////////////////////////////////////

            /* La partie IVideoWindow dépend du GraphBuilder uniquement
            * qui lui ne dépend de rien */

            //Création Du MediaControl (play, pause, stop) et de la fenêtre où la vidéo sera affichée
            MediaControl = (IMediaControl)GraphBuilder;
            IVideoWindow videoWin = (IVideoWindow)GraphBuilder;
            /////////////////////////////////////////////////

            //Récupération du filtre en video grâce au captureGraph et au filtre
            //on donne au captureGraph un GraphBuilder
            //on donne au GraphBuilder 1 ou plusieurs filtres
            //le captureGraph peut alors user de ces filtres pour les connecter ensemble
            hr = CaptureGraph.SetFiltergraph(GraphBuilder);
            hr = GraphBuilder.AddFilter(FiltreVideoInput, "Capture Video");
            hr = CaptureGraph.RenderStream(ref categorie, ref media, FiltreVideoInput, null, null);
            /////////////////////////////////////////////////

            //Positionnement et dimensionnement de la fenêtre
            videoWin.put_Owner(panel.Handle);
            hr = videoWin.SetWindowPosition(0, 0, panel.Width, panel.Height);
            videoWin.put_WindowStyle(0x40000000);
            hr = videoWin.put_Visible(1);
            ///////////////////////////////////////////////////////

            //hr = MediaControl.Run();
            if (!test)
                this.MediaControlL = MediaControl;
            else
                this.MediaControlR = MediaControl;
        }



        public void RunCam(object toto)
        {
            //MessageBox.Show("thread lancé");
            ((IMediaControl)toto).Run();
            //MessageBox.Show("FINI");
        }

        private void testThread()
        {
            Thread Thread = new Thread(this.RunCam);
            Thread.Start(this.MediaControlL);
            //Thread.Sleep(100);
            Thread Thread2 = new Thread(this.RunCam);
            Thread2.Start(this.MediaControlR);
        }

        private void MykeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == 27)
                this.Close();


            // Des test pour re-afficher l'image quand on appuie sur une touche
            /*DsDev.GetDevicesOfCat(FilterCategory.VideoInputDevice, out Webcamliste); //pourquoi je refait ca ? parce que l'attribut "mon" des WebcamL et WebcamR et webcamlist[x -1]
            CamAttrib(Webcamliste); // et webcamlist[x] sont mis a null automatiquement quand on les utilise, donc je les reinitialise
            Bitmap gauche = (Bitmap)testCam.Capture.GetImage(WebcamL); //normalement ca devrait rechopper l'image actuel, mais non ca fait null
            Bitmap droite = (Bitmap)testCam.Capture.GetImage(WebcamR);//normalement ca devrait rechopper l'image actuel, mais non ca fait null
            if (gauche != null)
                this.image1.Image = gauche;
            if (droite != null)
                this.image2.Image = droite;*/

            /*
            if (e.KeyChar.Equals(Keys.Right))
                this.switchEye();
            */
             if (e.KeyChar == 113)
                 this.ActiveLeftEye();
             if (e.KeyChar == 100)
                 this.ActiveRightEye();
             if (e.KeyChar == 115)
                 this.switchEye();
             if (e.KeyChar == 32)
                 MessageBox.Show("Putain de directShow de merde pourquoi tu peux pas afficher deux cam en meme temps!!!");
             if (e.KeyChar == 48)
                 this.testThread();
        }

        private void CamAttrib(ArrayList Webcamliste)
        {
            int j = -1;
            for (int i = 0; i < Webcamliste.Count; ++i)
            {
                if (((DsDevice)Webcamliste[i]).Name.LastIndexOf("Vimicro") != -1)
                    j = i;
            }
            if (j == -1)
            {
                MessageBox.Show("Branche les lunettes enculé !!! ");
                this.Close();
            }
            this.WebcamL = (DsDevice)Webcamliste[j - 1];
            this.WebcamR = (DsDevice)Webcamliste[j];       
        }

        private void switchEye()
        {
            if (this.TheSwitcher)
            {
                this.TheSwitcher = false;
                this.MediaControlR.Stop();
                this.MediaControlL.Run();
            }
            else
            {
                this.TheSwitcher = true;
                this.MediaControlL.Stop();
                this.MediaControlR.Run();
            }
        }

        private void Form1_Load(object sender, System.EventArgs e)
        {
            //ArrayList Webcamliste;
            if(!DsUtils.IsCorrectDirectXVersion() ) // teste si la version de DirectX est OK
            {
                MessageBox.Show( this, "DirectX 9.0 n'est pas installé sur votre système", "Erreur", MessageBoxButtons.OK, MessageBoxIcon.Stop );
                this.Close();
                return;
            }
            if(!DsDev.GetDevicesOfCat( FilterCategory.VideoInputDevice, out Webcamliste) )
            {
                MessageBox.Show( this, "Aucune webcam n'a été trouvée", "Erreur", MessageBoxButtons.OK, MessageBoxIcon.Stop );
                this.Close();
                return;
            }
            else
                CamAttrib(Webcamliste);

            // Parametrage
            this.IWRHandle = IWRSTEREO_Open(); //just pour tester
            IWRSTEREO_SetStereo(this.IWRHandle, true);//just pour tester (aucun effet visible)
           
            /*Bitmap gauche = (Bitmap)testCam.Capture.GetImage(WebcamL);
            Bitmap droite = (Bitmap)testCam.Capture.GetImage(WebcamR);

            this.image1.Image = gauche;
            this.image2.Image = droite;*/

            Config(WebcamL, panel1, false);
            Config(WebcamR, panel2, true);
            
        }
    }
}
